本次使用新聞範例一樣式前幾天就出現過的 接手中介法草案?唐鳳:監理業務不屬於數位部
將本篇新聞內容以 List[str]
表示:
content = ['媒體關注數位部部長唐鳳對數位中介服務法看法,唐鳳表示,監理業務不屬於數位部範圍,面對大型跨境數位平台,最重要的是要確保現實世界中覺得合理的價值,平台上也應該符合相關的社會價值,遵守常規。',
'唐鳳今天中午接受震傳媒網路節目「新聞不芹菜」的視訊採訪,主持人黃光芹詢問唐鳳對於數位中介服務法(中介法)看法,是否反對立法。',
'唐鳳表示,中介法主要是監理非法言論部份,在數位部揭牌當天就提到,數位部的工作是扮演採油門角色,監理部份並不是數位部業務。',
'唐鳳直言,NCC日前提出數位中介服務法草案,還在NCC對外界徵詢草案的階段,目前NCC也提到會整理相關民間意見、歸零思考,把草案退回到工作小組。草案先前也還沒有提到政院討論,沒有要表態的問題。',
'唐鳳指出,面對跨境大型數位平台時,最重要價值是要確保現實社會覺得合理的價值,在大型數位平台上也應該符合相關的社會價值。',
'唐鳳舉例,監察院會公布競選期間政治獻金花費,選罷法也規範境外者不能給予候選人政治獻金,必須要符合透明度以及不能收國外的錢。前幾年有人透過數位平台下廣告、幫特定候選人打廣告,等於繞過政治獻金法的規範。',
'唐鳳指出,後來也有跟平台溝通,不管在美國是什麼樣的規範,在台灣就是要揭露、不能收國外的錢,不能到平台上就不遵守相關常規。平台後來在2019年做修正,舉這個例子是要說明,還是要從社會怎麼樣合適出發,這些跨境科技平台要配合社會價值,而不是擾亂社會價值、反過來要求配合平台。']
這一段採用 [Day-13] 以 Spacy 的 DependencyMatcher 找出意見持有者、動詞、句子範圍 所介紹的方法,將其做些更動變成下面的程式碼:
import stanza
import spacy_stanza
from ckip_transformers.nlp import CkipPosTagger, CkipNerChunker
import spacy
from spacy import displacy
from spacy.tokens import Span
from spacy.matcher import DependencyMatcher
from itertools import chain
import json
import uuid
stanza.download("zh-hant")
nlp = spacy_stanza.load_pipeline("xx", lang='zh-hant')
def add_ner(doc):
ner_driver = CkipNerChunker(model="bert-base")
ner = ner_driver([str(doc)], show_progress=False)
ner_spans = []
for entity in ner[0]:
span = doc.char_span(entity.idx[0], entity.idx[1], label=entity.ner)
if span is None:
span = doc.char_span(entity.idx[0], entity.idx[1] + 1, label=entity.ner)
ner_spans.append(span)
orig_ents = list(doc.ents)
doc.ents = orig_ents + ner_spans
def add_ckip_tag(doc):
pos_driver = CkipPosTagger(model="bert-base")
words = [[str(token) for token in doc]]
pos = pos_driver(words, show_progress=False)
for token, ckip_pos in zip(doc, pos[0]):
token.tag_ = ckip_pos
version = "v0"
pattern = [
# anchor token: VE
{
"RIGHT_ID": "VE",
"RIGHT_ATTRS": {"TAG": "VE"}
},
# founded -> subject
{
"LEFT_ID": "VE",
"REL_OP": ">",
"RIGHT_ID": "who_root",
"RIGHT_ATTRS": {"DEP": "nsubj"}
},
# "founded" follows "initially"
{
"LEFT_ID": "VE",
"REL_OP": ">",
"RIGHT_ID": "idea_root",
"RIGHT_ATTRS": {"DEP": {"IN": ["ccomp", "parataxis"]}}
}
]
matcher = DependencyMatcher(nlp.vocab, validate=True)
matcher.add(f"{version}", [pattern])
pre_annotations = []
final_docs = []
for doc in nlp.pipe(content):
pre_annotation_data = {
"data": {
"title": title,
"paragraph": str(doc)
},
"predictions": [
{
"model_version": f"{version}",
"result": []
}
]
}
add_ner(doc)
add_ckip_tag(doc)
matches = matcher(doc)
matches_sorted = sorted(matches, key=lambda x: abs(x[1][0] - x[1][1]))
if len(matches_sorted) > 1:
matches_sorted = [match for match in matches_sorted if (match[1][0] == matches_sorted[0][1][0] and match[1][1] == matches_sorted[0][1][1])]
if len(matches_sorted) > 0:
first_match = matches_sorted[0]
VE_id = first_match[1][0]
who_root_id = first_match[1][1]
VE_span = Span(doc, VE_id, VE_id+1, label="VERB")
who_root_span = Span(doc, doc[who_root_id].left_edge.i, doc[who_root_id].right_edge.i+1, label="WHO")
idea_spans = []
for match in matches_sorted:
match_id, token_ids = match
idea_root_id = token_ids[2]
idea_spans.append(Span(doc, doc[idea_root_id].left_edge.i, doc[idea_root_id].right_edge.i+1, label="OPINION"))
doc.spans["sc"] = spacy.util.filter_spans([VE_span, who_root_span] + idea_spans)
for span in doc.spans["sc"]:
print(span.text, span.label_)
pre_annotation_data["predictions"][0]["result"].append(
{
"id": str(uuid.uuid1()),
"from_name": "opinion_label",
"to_name": "a_paragraph",
"type": "labels",
"value": {
"start": span.start_char,
"end": span.end_char,
"text": span.text,
"labels": [
span.label_
]
}
}
)
else:
doc.spans["sc"] = []
final_docs.append(doc)
pre_annotations.append(pre_annotation_data)
html = displacy.render(final_docs, style="span", jupyter=False, page=True)
file_name = f"opinion_html/{version}/{title}.html"
with open(f"{file_name}", "w") as f:
f.write(html)
with open(f"pre_annotations/{version}/{title}.json", "w") as f:
json.dump(pre_annotations, f, ensure_ascii=False)
上方程式碼在意見持有者、意見動詞、意見句的標注任務上添加下列新功能:
賦予目前的意見持有者、意見動詞、意見句的標注方法一個版本號:
version = "v0"
來設定將意見持有者、意見動詞、意見句的標注存成 html
final_docs = []
初始化一個用於儲存 doc
的 list 。doc in nlp.pipe(content)
迴圈,doc
將依序被賦予 content
中的每一段文字內容,並在 final_docs.append(doc)
的位置被加入到 final_docs
。html = displacy.render(final_docs, style="span", jupyter=False, page=True)
將 final_docs
中每個 doc
的標注結果轉成 html,再透過以下程式碼儲存:
file_name = f"opinion_html/{version}/{title}.html"
with open(f"{file_name}", "w") as f:
f.write(html)
將意見持有者、意見動詞、意見句的標注以 Label Studio 的輸入格式存成 json
pre_annotations = []
初始化一個用於儲存整篇新聞標註結果的 list。pre_annotation_data = {
"data": {
"title": title,
"paragraph": str(doc)
},
"predictions": [
{
"model_version": f"{version}",
"result": []
}
]
}
pre_annotation_data["predictions"][0]["result"].append(
{
"id": str(uuid.uuid1()),
"from_name": "opinion_label",
"to_name": "a_paragraph",
"type": "labels",
"value": {
"start": span.start_char,
"end": span.end_char,
"text": span.text,
"labels": [
span.label_
]
}
}
)
pre_annotations.append(pre_annotation_data)
將一段文字的的標注結果存到整篇新聞標註結果的 pre_annotations
。pre_annotations
所儲存的標注結果儲存成 json
with open(f"pre_annotations/{version}/{title}.json", "w") as f:
json.dump(pre_annotations, f, ensure_ascii=False)
點選此連結,以網頁形式查看標注結果
觀察用上面程式碼所產生的 json,每段文字內容都會有以下結構:
[
{
"data": {
"title": "接手中介法草案?唐鳳:監理業務不屬於數位部",
"paragraph": "媒體關注數位部部長唐鳳對數位中介服務法看法,唐鳳表示,監理業務不屬於數位部範圍,面對大型跨境數位平台,最重要的是要確保現實世界中覺得合理的價值,平台上也應該符合相關的社會價值,遵守常規。"
},
"predictions": [
{
"model_version": "v0",
"result": [
{
"id": "c4db7030-40d0-11ed-98a8-acde48001122",
"from_name": "opinion_label",
"to_name": "a_paragraph",
"type": "labels",
"value": {
"start": 22,
"end": 24,
"text": "唐鳳",
"labels": [
"WHO"
]
}
},
{
"id": "c4db72f6-40d0-11ed-98a8-acde48001122",
"from_name": "opinion_label",
"to_name": "a_paragraph",
"type": "labels",
"value": {
"start": 24,
"end": 26,
"text": "表示",
"labels": [
"VERB"
]
}
},
{
"id": "c4db74e0-40d0-11ed-98a8-acde48001122",
"from_name": "opinion_label",
"to_name": "a_paragraph",
"type": "labels",
"value": {
"start": 27,
"end": 92,
"text": "監理業務不屬於數位部範圍,面對大型跨境數位平台,最重要的是要確保現實世界中覺得合理的價值,平台上也應該符合相關的社會價值,遵守常規",
"labels": [
"OPINION"
]
}
}
]
}
]
},
{
"data": {
"title": "接手中介法草案?唐鳳:監理業務不屬於數位部",
"paragraph": "唐鳳今天中午接受震傳媒網路節目「新聞不芹菜」的視訊採訪,主持人黃光芹詢問唐鳳對於數位中介服務法(中介法)看法,是否反對立法。"
},
"predictions": [
{
"model_version": "v0",
"result": []
}
]
},
...
省略
...
]
label-studio start
<View>
<Labels name="opinion_label" toName="a_paragraph">
<Label value="VERB" background="red"/>
<Label value="OPINION" background="orange"/>
<Label value="WHO" background="green"/>
</Labels>
<Header value="$title"/>
<Text name="a_paragraph" value="$paragraph"/>
</View>
回到主頁面,點選其中一個即可查看標注結果